import { useState, createContext, useContext, useReducer } from 'react';
import './App.css';

interface CountContextType {
  num: number;
  dispatch: React.Dispatch<{ type: string; num2: number }>;
}

const CountContext = createContext<CountContextType>({
  num: 0,
  dispatch: () => {} // 这里可以保持不变，因为它是默认值
});

function App() {
  console.log('render app');

  /*
    Reducer 函数接收两个参数：当前状态 state 和动作 action。
    根据 action 的类型返回新的状态。
  */
  const reduce = (state: number, action: { type: string; num2: number }) => {
    switch (action.type) {
      case 'add':
        return state + action.num2;
      case 'sub':
        return state - action.num2;
      default:
        return state;
    }
  };

  /**
   * useReducer 是 React 中的一个 Hook，用于管理复杂的状态逻辑。它类似于 Redux 中 的 reducer 函数，适用于状态逻辑较为复杂的场景。useReducer 可以帮助你将状态逻辑从组件中分离出来，使代码更加清晰和可维护。
   */
  const [count, setCount] = useState(0);
  /*
  * 调用 useReducer 钩子，传入 reducer 函数和初始状态。
    useReducer 返回一个数组，第一个元素是当前状态，第二个元素是 dispatch 函数，用于触发状态更新。
  */
  const [num, dispatch] = useReducer(reduce, count);

  return (
    <>
      <div className='card'>
        <h1>useReducer 使用方法</h1>
        <br />

        <CountContext.Provider value={{ num, dispatch }}>
          <Son />
          <Child />
        </CountContext.Provider>
      </div>
    </>
  );
}

const Son = () => {
  console.log('render son');
  const { dispatch }: CountContextType = useContext(CountContext);

  // 子组件 Son 通过 useContext 获取 dispatch 函数，用于触发状态更新。
  // handleAdd 和 handleSub 函数通过 dispatch 发送不同的 action 来更新状态。
  const handleAdd = (num: number) => {
    dispatch({ type: 'add', num2: num });
  };
  const handleSub = (num: number) => {
    dispatch({ type: 'sub', num2: num });
  };
  return (
    <div>
      <button onClick={() => handleAdd(2)}>加2</button>
      <button onClick={() => handleSub(1)}>减1</button>
    </div>
  );
};

const Child = () => {
  console.log('render children');
  return (
    <div>
      <CountContext.Consumer>
        {({ num }) => <div>第二个组件收到的值： {num}</div>}
      </CountContext.Consumer>
    </div>
  );
};

export default App;